package com.agger.harmonyosthemeseditor.intelligent;

import com.agger.harmonyosthemeseditor.ResourceTable;
import com.agger.harmonyosthemeseditor.userinterface.ResourceTool;
import ohos.agp.colors.HsvColor;
import ohos.agp.colors.RgbColor;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.media.image.common.ImageInfo;
import ohos.media.image.common.Position;

import java.util.ArrayList;
import java.util.List;

public class ColorManager
{
    private static float[] maxSaturation,maxBrightness,minSaturation,minBrightness,avgSaturation,avgBrightness,SaturationIndex,BrightnessIndex,SaturationFixRate,BrightnessFixRate;
    private static List<Float>[] allSaturation=new ArrayList[]{new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>()},allBrightness=new ArrayList[]{new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>(),new ArrayList<Float>()};
    private static int[] SaturationDifferMode,BrightnessDifferMode;
    private static final float MinSaturation() {return 36f;}
    private static final float MinBrightness(){return 28f;}
    private static final float MinAvgSaturation(){return 42f;}
    private static final float MinAvgBrightness(){return 36f;}

    public static void Init(PixelMap mPixelMap)
    {
        maxSaturation = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        minSaturation = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        avgSaturation = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        SaturationIndex = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        SaturationFixRate = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        allSaturation[0].clear();
        allSaturation[1].clear();
        allSaturation[2].clear();
        allSaturation[3].clear();
        allSaturation[4].clear();
        allSaturation[5].clear();
        maxBrightness = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        minBrightness = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        avgBrightness = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        BrightnessIndex = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        BrightnessFixRate = new float[]{-1f, -1f, -1f, -1f, -1f, -1f};
        allBrightness[0].clear();
        allBrightness[1].clear();
        allBrightness[2].clear();
        allBrightness[3].clear();
        allBrightness[4].clear();
        allBrightness[5].clear();
        SaturationDifferMode = new int[]{0,0,0,0,0,0};
        BrightnessDifferMode = new int[]{0,0,0,0,0,0};
        ImageInfo mImageInfo = mPixelMap.getImageInfo();
        int mWidth = mImageInfo.size.width;
        int mHeight = mImageInfo.size.height;
        for(int h = 0; h < mHeight; h++)
        {
            for(int w = 0; w < mWidth; w++)
            {
                HsvBox mHsvBox = getHsvBox(mPixelMap.readPixel(new Position(w,h)));
                float mSaturation = mHsvBox.getSaturation();
                float mBrightness = mHsvBox.getValue();
                int ColorSpace = (int)(mHsvBox.getHue()/60f);
                if(ColorSpace>5||ColorSpace<0)ColorSpace=0;
                if(mSaturation>MinSaturation()&&mBrightness>MinBrightness())
                {
                    if(maxSaturation[ColorSpace]==-1f)
                    {
                        maxSaturation[ColorSpace] = mSaturation;
                        minSaturation[ColorSpace] = mSaturation;
                        allSaturation[ColorSpace].add(mSaturation);
                        maxBrightness[ColorSpace] = mBrightness;
                        minBrightness[ColorSpace] = mBrightness;
                        allBrightness[ColorSpace].add(mBrightness);
                    }
                    else
                    {
                        if(mSaturation>maxSaturation[ColorSpace])maxSaturation[ColorSpace] = mSaturation;
                        else if(mSaturation<minSaturation[ColorSpace])minSaturation[ColorSpace] = mSaturation;
                        allSaturation[ColorSpace].add(mSaturation);
                        if(mBrightness>maxBrightness[ColorSpace])maxBrightness[ColorSpace] = mBrightness;
                        else if(mBrightness<minBrightness[ColorSpace])minBrightness[ColorSpace] = mBrightness;
                        allBrightness[ColorSpace].add(mBrightness);
                    }
                }
            }
        }
        for(int i = 0;i < 6;i++)
        {
            avgSaturation[i] = allSaturation[i].size()>0?VariableTool.getAverage(allSaturation[i]):-1f;
            allSaturation[i].clear();
            avgBrightness[i] = allBrightness[i].size()>0?VariableTool.getAverage(allBrightness[i]):-1f;
            allBrightness[i].clear();
            if(avgSaturation[i]!=-1f&&avgBrightness[i]!=-1f)
            {
                SaturationIndex[i] = ((maxSaturation[i]+minSaturation[i])/2f);
                if(SaturationIndex[i]>avgSaturation[i])
                {
                    float fixedMaxSaturation = avgSaturation[i]*2f-minSaturation[i];
                    if(fixedMaxSaturation<maxSaturation[i])
                    {
                        if(((maxSaturation[i]-fixedMaxSaturation)/(avgSaturation[i]-minSaturation[i]))>0.08f)
                        {
                            SaturationFixRate[i] = (fixedMaxSaturation+(avgSaturation[i]-minSaturation[i])*0.08f-avgSaturation[i])/(maxSaturation[i]-avgSaturation[i]);
                            SaturationDifferMode[i]=1;
                        }
                    }
                }
                else if(SaturationIndex[i]<avgSaturation[i])
                {
                    float fixedMinSaturation = avgSaturation[i]*2f-maxSaturation[i];
                    if(fixedMinSaturation>minSaturation[i])
                    {
                        if(((fixedMinSaturation-minSaturation[i])/(maxSaturation[i]-avgSaturation[i]))>0.08f)
                        {
                            SaturationFixRate[i] = (avgSaturation[i]-(fixedMinSaturation-(maxSaturation[i]-avgSaturation[i])*0.08f))/(avgSaturation[i]-minSaturation[i]);
                            SaturationDifferMode[i]=-1;
                        }
                    }
                }
                BrightnessIndex[i] = ((maxBrightness[i]+minBrightness[i])/2f);
                if(BrightnessIndex[i]>avgBrightness[i])
                {
                    float fixedMaxBrightness = avgBrightness[i]*2f-minBrightness[i];
                    if(fixedMaxBrightness<maxBrightness[i])
                    {
                        if(((maxBrightness[i]-fixedMaxBrightness)/(avgBrightness[i]-minBrightness[i]))>0.08f)
                        {
                            BrightnessFixRate[i] = (fixedMaxBrightness+(avgBrightness[i]-minBrightness[i])*0.08f-avgBrightness[i])/(maxBrightness[i]-avgBrightness[i]);
                            BrightnessDifferMode[i]=1;
                        }
                    }
                }
                else if(BrightnessIndex[i]<avgBrightness[i])
                {
                    float fixedMinBrightness = avgBrightness[i]*2f-maxBrightness[i];
                    if(fixedMinBrightness>minBrightness[i])
                    {
                        if(((fixedMinBrightness-minBrightness[i])/(maxBrightness[i]-avgBrightness[i]))>0.08f)
                        {
                            BrightnessFixRate[i] = (avgBrightness[i]-(fixedMinBrightness-(maxBrightness[i]-avgBrightness[i])*0.08f))/(avgBrightness[i]-minBrightness[i]);
                            BrightnessDifferMode[i]=-1;
                        }
                    }
                }
            }
            if(SaturationDifferMode[i]==0&&BrightnessDifferMode[i]==0)
            {
                avgSaturation[i] = -1f;
                avgBrightness[i] = -1f;
            }
        }
    }

    public static int getFixedColor(int mColor)
    {
        HsvBox mHsvBox = getHsvBox(mColor);
        float mHue = mHsvBox.getHue();
        int ColorSpace = (int)(mHue/60f);
        if(ColorSpace>5||ColorSpace<0)ColorSpace=0;
        if(avgSaturation[ColorSpace]==-1f||avgBrightness[ColorSpace]==-1f)
        {
            return mColor;
        }
        else
        {
            float mSaturation = mHsvBox.getSaturation();
            if(mSaturation<=MinSaturation()) return mColor;
            float mBrightness = mHsvBox.getValue();
            if(mBrightness<=MinBrightness()) return mColor;
            int mAlpha = RgbColor.fromArgbInt(mColor).getAlpha();
            float nSaturation = mSaturation;
            if(SaturationDifferMode[ColorSpace]==1)
            {
                if(mSaturation>avgSaturation[ColorSpace])
                nSaturation = avgSaturation[ColorSpace]+(mSaturation-avgSaturation[ColorSpace])*SaturationFixRate[ColorSpace];
            }
            else if(SaturationDifferMode[ColorSpace]==-1)
            {
                if(mSaturation<avgSaturation[ColorSpace])
                    nSaturation = avgSaturation[ColorSpace]-(avgSaturation[ColorSpace]-mSaturation)*SaturationFixRate[ColorSpace];
            }
            float nBrightness = mBrightness;
            if(BrightnessDifferMode[ColorSpace]==1)
            {
                if(mBrightness>avgBrightness[ColorSpace])
                    nBrightness = avgBrightness[ColorSpace]+(mBrightness-avgBrightness[ColorSpace])*BrightnessFixRate[ColorSpace];
            }
            else if(BrightnessDifferMode[ColorSpace]==-1)
            {
                if(mBrightness<avgBrightness[ColorSpace])
                    nBrightness = avgBrightness[ColorSpace]-(avgBrightness[ColorSpace]-mBrightness)*BrightnessFixRate[ColorSpace];
            }
            return HsvColor.toColor(mAlpha,mHue,nSaturation,nBrightness);
        }
    }

    public static int getAverageColor(int nColor,int mColor)
    {
        HsvBox nHsvBox = getHsvBox(nColor);
        HsvBox mHsvBox = getHsvBox(mColor);
        int avgAlpha = (int)((RgbColor.fromArgbInt(nColor).getAlpha()+RgbColor.fromArgbInt(mColor).getAlpha())/2f);
        float avgHue = (nHsvBox.getHue()+mHsvBox.getHue())/2f;
        float avgSaturation = (nHsvBox.getSaturation()+mHsvBox.getSaturation())/2f;
        float avgBrightness = (nHsvBox.getValue()+mHsvBox.getValue())/2f;
        return HsvColor.toColor(avgAlpha,avgHue,avgSaturation,avgBrightness);
    }

    public static boolean isSimilarHue(float Hue,float mHue,float dValue)
    {
        return Math.abs(Hue-mHue)<=dValue||(360f-Math.abs(Hue-mHue))<=dValue;
    }

    public static boolean isSimilarSaturation(float Saturation,float mSaturation,float dValue)
    {
        return Math.abs(Saturation-mSaturation)<=dValue;
    }

    public static boolean isSimilarBrightness(float Brightness,float mBrightness,float dValue)
    {
        return Math.abs(Brightness-mBrightness)<=dValue;
    }

    public static boolean isSimilarColor(int nColor,int mColor,float dValue_Hue,float dValue_Saturation,float dValue_Brightness)
    {
        HsvColor nHsvColor = HsvColor.toHSV(nColor);
        float nHue = nHsvColor.getHue();
        float nSaturation = nHsvColor.getSaturation();
        float nBrightness = nHsvColor.getValue();
        HsvColor mHsvColor = HsvColor.toHSV(mColor);
        float mHue = mHsvColor.getHue();
        float mSaturation = mHsvColor.getSaturation();
        float mBrightness = mHsvColor.getValue();
        return isSimilarHue(nHue,mHue,dValue_Hue)&&isSimilarSaturation(nSaturation,mSaturation,dValue_Saturation)&&isSimilarBrightness(nBrightness,mBrightness,dValue_Brightness);
    }

    public static class HsvBox
    {
        private float mH,mS,mV;
        public HsvBox(float Hue,float Saturation,float Brightness)
        {
            mH = Hue;
            mS = Saturation;
            mV = Brightness;
        }
        public float getHue(){return mH;}
        public float getSaturation(){return mS;}
        public float getValue(){return mV;}
    }

    //由于鸿蒙自带的HsvColor方法，在遇到Hue值为300-360的色彩会全部返回0，这里重写Hsv算法
    public static HsvBox getHsvBox(int mColor)
    {
        RgbColor c = RgbColor.fromArgbInt(mColor);
        int R = c.getRed();
        int G = c.getGreen();
        int B = c.getBlue();
        int max = Math.max(Math.max(R,G),B);
        int min = Math.min(Math.min(R,G),B);
        float V = max*100f/255f;
        float S = (max-min)*100f/max;
        float H = 0;
        if(R==max) H=(G-B)*60f/(max-min);
        else if(G==max) H=120f+(B-R)*60f/(max-min);
        else if(B==max) H=240f+(R-G)*60f/(max-min);
        if(H<0) H+=360f;
        return new HsvBox(H,S,V);
    }

    public static String getColorHex(RgbColor mColor)
    {
        String R = "00";
        if(mColor.getRed()>0) R = Integer.toHexString(mColor.getRed());
        if(R.length()<2) R = "0"+R;
        String G = "00";
        if(mColor.getGreen()>0) G = Integer.toHexString(mColor.getGreen());
        if(G.length()<2) G = "0"+G;
        String B = "00";
        if(mColor.getBlue()>0) B = Integer.toHexString(mColor.getBlue());
        if(B.length()<2) B = "0"+B;
        return (R+G+B).toUpperCase();
    }

    public static String getColorHex(int mColor)
    {
        return getColorHex(RgbColor.fromArgbInt(mColor));
    }

    public static boolean isDarkMode(Context context)
    {
        return ResourceTool.getColor(context, ResourceTable.Color_dawnlighti_color_mode,-1)==-16777216;
    }
}